home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / util / misc / ReportPlus.lha / reportplus / source / f8.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-25  |  37.7 KB  |  1,259 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <proto/exec.h>
  4. #include <intuition/intuition.h>
  5. #include <intuition/gadgetclass.h>
  6. #include <proto/intuition.h>
  7. #include <libraries/gadtools.h>
  8. #include <proto/gadtools.h>
  9. #include <dos/dos.h>
  10. #include <dos/exall.h>
  11. #include <dos/dostags.h>
  12. #include <proto/dos.h>
  13. #include <graphics/gfx.h>
  14. #include <clib/graphics_protos.h>
  15. #include <clib/alib_protos.h>
  16. #include <libraries/asl.h>
  17. #include <clib/asl_protos.h>
  18.  
  19. #include <ctype.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "rp.h"
  23.  
  24. #define SIZELISTVIEWCHARS 37
  25. #define TRUNCATE          50
  26. #define LVTRUNCATE        25
  27.  
  28. /* Limitations:
  29.    LIMIT_DIRS (top-level list entries).
  30.    MAX_FILES (total files/dirs in path). */
  31.  
  32. MODULE void pop(void);
  33. MODULE void push(STRPTR name, ULONG theindex);
  34. MODULE void subdir(ULONG theindex);
  35. MODULE void parent(void);
  36. MODULE void root(void);
  37. MODULE void pathasl(void);
  38. MODULE void pathstring(void);
  39. MODULE void comma(ULONG value);
  40. MODULE ABOOL dirasl(void);
  41. MODULE void showduplicates(void);
  42. MODULE void addduplicate(STRPTR path, STRPTR filename);
  43. MODULE void flipfind(ABOOL keyboard);
  44. MODULE void clearlist(struct List* ListPtr);
  45. MODULE void writeline(void);
  46.  
  47. IMPORT struct Library*     ListBrowserBase;
  48. IMPORT ABOOL               fillwindows;
  49. IMPORT TEXT                asldir[VLONGFIELD + 1],
  50.                            aslresult[MEDFIELD + 1];
  51. // we only use LIMIT_DIRS worth of FileNamePtrs.
  52. MODULE STRPTR              FileNamePtr[LIMIT_FILES];
  53. MODULE STRPTR              DirNamePtr[LIMIT_DIRS];
  54. MODULE TEXT                logstring[256 + 1];
  55. MODULE UBYTE               valuestring[11],
  56.                            commastring[14];
  57. IMPORT  SBYTE              page;
  58. IMPORT  ULONG              wbval;
  59. MODULE  ULONG              DirNamesAllocated  = 0,
  60.                            FileNamesAllocated = 0;
  61. IMPORT  TEXT               globalname[VLONGFIELD + 1];
  62. IMPORT  TEXT               weekdaystring[10],
  63.                            datestring[10],
  64.                            timestring[9];
  65. IMPORT struct SharedStruct shared;
  66. IMPORT struct NewGadget    Gadget;
  67. IMPORT struct Screen*      ScreenPtr;
  68. IMPORT struct Window*      MainWindowPtr;
  69. IMPORT struct Gadget      *BU99_Left,
  70.                           *BU99_Right,
  71.                           *ST99_Output,
  72.                           *BU99_OutputASL,
  73.                           *CB99_Log,
  74.                           *BU99_Update,
  75.                           *BU99_Stop,
  76.                           *GListPtr,
  77.                           *PrevGadPtr;
  78. IMPORT struct ExAllData*   EADataPtr;
  79. IMPORT WORD                ysize;
  80.  
  81. #define MAX_FILES (128 * 1024)
  82.  
  83. MODULE struct List         EmptyList, SizeList, SizeResultList;
  84. MODULE struct Gadget      *LV81_DupListview  = NULL,
  85.                           *LV81_Listview = NULL,
  86.                           *CB81_Find     = NULL,
  87.                           *ST81_Path     = NULL,
  88.                           *BU81_PathASL  = NULL,
  89.                           *BU81_Root     = NULL,
  90.                           *BU81_Parent   = NULL,
  91.                           *TE81_Total    = NULL,
  92.                           *TE81_Free     = NULL;
  93. MODULE ULONG              dup            = 0;
  94. MODULE STRPTR*            TablePtr;
  95. MODULE UBYTE*             OffsetPtr;
  96. MODULE UBYTE              pathlength;
  97. MODULE BPTR               DirHandle      = NULL,
  98.                           FileHandle     = NULL;
  99.  
  100. MODULE struct
  101. {   ULONG entries, totalbytesval, freeval, stackentries;
  102.     TEXT  totalbytesstring[11], freestring[11],
  103.           oldpath[VLONGFIELD + 1], path[VLONGFIELD + 1];
  104.     ULONG bytes[LIMIT_DIRS], topdir[LIMIT_DIRS];
  105.     LONG  type[LIMIT_DIRS];
  106.     ABOOL finddup;
  107. } size;
  108. MODULE ABOOL stop;
  109.  
  110. AGLOBAL void size_init(void)
  111. {   strcpy(size.path, "RAM:");
  112.     size.finddup = FALSE;
  113.  
  114.     NewList(&EmptyList);
  115. }
  116.  
  117. AGLOBAL void size1(void)
  118. {   if (ysize >= 512)
  119.     {   verynewwindow
  120.         (   SIZE1WIDTH, 512, // @@: line up navigation buttons properly
  121.             "Report+: Path Size Report",
  122.             BUTTONIDCMP | STRINGIDCMP | LISTVIEWIDCMP
  123.         );
  124.     } else
  125.     {   verynewwindow
  126.         (   SIZE1WIDTH, SIZE1HEIGHT,
  127.             "Report+: Path Size Report",
  128.             BUTTONIDCMP | STRINGIDCMP | LISTVIEWIDCMP
  129.         );
  130.     }
  131.     if (fillwindows)
  132.     {   SetAPen(MainWindowPtr->RPort, 0);
  133.         RectFill(MainWindowPtr->RPort,  12,  44,  12 + 348,  44 + 126 - 3);     // LV81_Listview
  134.         RectFill(MainWindowPtr->RPort, 228, 168, 228 + 116, 168 + 12);          // TE81_Total
  135.         RectFill(MainWindowPtr->RPort, 228, 180, 228 + 116, 180 + 12);          // TE81_Free
  136.         if (ysize >= 512)
  137.         {   RectFill(MainWindowPtr->RPort,  10, 226,  10 + 620, 226 + 262 - 3); // LV81_DupListview
  138.         } else
  139.         {   RectFill(MainWindowPtr->RPort, 370, 116, 370 + 260, 116 + 76);      // LV81_DupListview
  140.     }   }
  141.  
  142.     if (ysize >= 512)
  143.     {   setgadget( 10, 226, 620, 262, NULL, NULL);
  144.     } else
  145.     {   setgadget(370, 116, 260,  76, NULL, NULL);
  146.     }
  147.  
  148.     LV81_DupListview = PrevGadPtr = (struct Gadget *) CreateGadget
  149.     (   LISTVIEW_KIND,
  150.         PrevGadPtr,
  151.         &Gadget,
  152.         GTLV_Labels, NULL,
  153.         GTLV_ReadOnly, TRUE,
  154.         GA_Disabled, !size.finddup,
  155.         TAG_DONE
  156.     );
  157.  
  158.     /* path */
  159.     setgadget(60, 20, 270, 12, "_Path:", NULL);
  160.     ST81_Path = PrevGadPtr = (struct Gadget *) CreateGadget
  161.     (   STRING_KIND,
  162.         PrevGadPtr,
  163.         &Gadget,
  164.         GTST_String, &(size.path),
  165.         GTST_MaxChars, VLONGFIELD,
  166.         GA_TabCycle, TRUE,
  167.         GT_Underscore, '_',
  168.         TAG_DONE
  169.     );
  170.     /* path... */
  171.     setgadget(332, 20, 28, 12, "_...", NULL);
  172.     BU81_PathASL = PrevGadPtr = (struct Gadget *) CreateGadget
  173.     (   BUTTON_KIND,
  174.         PrevGadPtr,
  175.         &Gadget,
  176.         GT_Underscore, '_',
  177.         TAG_DONE
  178.     );
  179.     // root
  180.     setgadget(12, 32, 174, 12, "_Root", NULL);
  181.     BU81_Root = PrevGadPtr = (struct Gadget *) CreateGadget
  182.     (   BUTTON_KIND,
  183.         PrevGadPtr,
  184.         &Gadget,
  185.         GT_Underscore, '_',
  186.         TAG_DONE
  187.     );
  188.     // parent
  189.     setgadget(186, 32, 174, 12, "P_arent", NULL);
  190.     BU81_Parent = PrevGadPtr = (struct Gadget *) CreateGadget
  191.     (   BUTTON_KIND,
  192.         PrevGadPtr,
  193.         &Gadget,
  194.         GT_Underscore, '_',
  195.         TAG_DONE
  196.     );
  197.  
  198.     setgadget(12, 44, 348, 126, NULL, NULL);
  199.     LV81_Listview = PrevGadPtr = (struct Gadget *) CreateGadget
  200.     (   LISTVIEW_KIND,
  201.         PrevGadPtr,
  202.         &Gadget,
  203.         GTLV_Labels, NULL,
  204.         TAG_DONE
  205.     );
  206.  
  207.     /* total bytes */
  208.     setgadget(228, 168, 116, 12, "Path bytes:", NULL);
  209.     TE81_Total = PrevGadPtr = (struct Gadget *) CreateGadget
  210.     (   TEXT_KIND,
  211.         PrevGadPtr,
  212.         &Gadget,
  213.         GTTX_Text, size.totalbytesstring,
  214.         GTTX_Border, TRUE,
  215.         TAG_DONE
  216.     );
  217.     /* free bytes */
  218.     setgadget(228, 180, 116, 12, "Free bytes:", NULL);
  219.     TE81_Free = PrevGadPtr = (struct Gadget *) CreateGadget
  220.     (   TEXT_KIND,
  221.         PrevGadPtr,
  222.         &Gadget,
  223.         GTTX_Text, size.freestring,
  224.         GTTX_Border, TRUE,
  225.         TAG_DONE
  226.     );
  227.  
  228.     // log to file?
  229.     setgadget(370, 45, 0, 0, "_Log to file?", PLACETEXT_RIGHT);
  230.     CB99_Log = PrevGadPtr = (struct Gadget *) CreateGadget
  231.     (   CHECKBOX_KIND,
  232.         PrevGadPtr,
  233.         &Gadget,
  234.         GTCB_Checked, shared.log,
  235.         GT_Underscore, '_',
  236.         TAG_DONE
  237.     );
  238.     /* output */
  239.     if (!shared.output[0])
  240.         strcpy(shared.output, "RAM:Report.txt");
  241.     setgadget(370, 72, 230, 12, "_Output pathname:", PLACETEXT_ABOVE);
  242.     ST99_Output = PrevGadPtr = (struct Gadget *) CreateGadget
  243.     (   STRING_KIND,
  244.         PrevGadPtr,
  245.         &Gadget,
  246.         GTST_String, &(shared.output),
  247.         GTST_MaxChars, LONGFIELD,
  248.         GA_TabCycle, TRUE,
  249.         GT_Underscore, '_',
  250.         TAG_DONE
  251.     );
  252.     /* output... */
  253.     setgadget(602, 72, 28, 12, "...", NULL);
  254.     BU99_OutputASL = PrevGadPtr = (struct Gadget *) CreateGadget
  255.     (   BUTTON_KIND,
  256.         PrevGadPtr,
  257.         &Gadget,
  258.         TAG_DONE
  259.     );
  260.  
  261.     // find duplicates?
  262.     if (ysize >= 512)
  263.     {   setgadget( 10, 226 - 14, 0, 0, "Find _duplicates?", PLACETEXT_RIGHT);
  264.     } else
  265.     {   setgadget(370, 102     , 0, 0, "Find _duplicates?", PLACETEXT_RIGHT);
  266.     }
  267.     CB81_Find = PrevGadPtr = (struct Gadget *) CreateGadget
  268.     (   CHECKBOX_KIND,
  269.         PrevGadPtr,
  270.         &Gadget,
  271.         GTCB_Checked, size.finddup,
  272.         GT_Underscore, '_',
  273.         TAG_DONE
  274.     );
  275.  
  276.     /* update */
  277.     setgadget(370, 20, 60, 12, "_Update", NULL);
  278.     BU99_Update = PrevGadPtr = (struct Gadget *) CreateGadget
  279.     (   BUTTON_KIND,
  280.         PrevGadPtr,
  281.         &Gadget,
  282.         GT_Underscore, '_',
  283.         TAG_DONE
  284.     );
  285.     /* stop */
  286.     setgadget(430, 20, 60, 12, "Stop", NULL);
  287.     BU99_Stop = PrevGadPtr = (struct Gadget *) CreateGadget
  288.     (   BUTTON_KIND,
  289.         PrevGadPtr,
  290.         &Gadget,
  291.         GA_Disabled, TRUE,
  292.         TAG_DONE
  293.     );
  294.  
  295.     drawgadgets((UWORD) ~0);
  296.  
  297.     if (!shared.log)
  298.     {   GT_SetGadgetAttrs
  299.         (   ST99_Output,
  300.             MainWindowPtr, NULL,
  301.             GA_Disabled, TRUE,
  302.             TAG_DONE
  303.         );
  304.         GT_SetGadgetAttrs
  305.         (   BU99_OutputASL,
  306.             MainWindowPtr, NULL,
  307.             GA_Disabled, TRUE,
  308.             TAG_DONE
  309.         );
  310.     }
  311.     updatesize();
  312.     ActivateGadget(ST81_Path, MainWindowPtr, NULL);
  313.     loop();
  314.     strcpy
  315.     (   shared.output,
  316.         ((struct StringInfo *) ST99_Output->SpecialInfo)->Buffer
  317.     );
  318.     closewindow();
  319.     size_exit();
  320. }
  321.  
  322. AGLOBAL void updatesize(void)
  323. {   BOOL                  more; // note that it is BOOL, not ABOOL
  324.     TEXT                  tempstring1[16], tempstring2[SIZELISTVIEWCHARS + 1],
  325.                           tempstring3[VLONGFIELD + 1], tempname[LONGFIELD + 1];
  326.     ULONG                 i, j, tempbytes;
  327.     LONG                  templength, temptype; // these both MUST be signed
  328.     ABOOL                 failed      = FALSE;
  329.     struct FileInfoBlock* FIBPtr      = NULL;
  330.     struct InfoData*      InfoDataPtr = NULL;
  331.     struct ExAllControl*  eac         = NULL;
  332.     struct ExAllData*     ead;
  333.  
  334.     clearlist(&SizeList);
  335.  
  336.     // 1: (Un)ghost relevant gadgets, for duration of the operation.
  337.  
  338.     stop = FALSE;
  339.     GT_SetGadgetAttrs
  340.     (   BU99_Update,
  341.         MainWindowPtr, NULL,
  342.         GA_Disabled, TRUE,
  343.         TAG_DONE
  344.     );
  345.     GT_SetGadgetAttrs
  346.     (   BU99_Stop,
  347.         MainWindowPtr, NULL,
  348.         GA_Disabled, FALSE,
  349.         TAG_DONE
  350.     );
  351.     GT_SetGadgetAttrs
  352.     (   BU99_Right,
  353.         MainWindowPtr, NULL,
  354.         GA_Disabled, TRUE,
  355.         TAG_DONE
  356.     );
  357.  
  358.     // 2: Now we get a Lock() on the path.
  359.  
  360.     size.stackentries = size.entries = 0;
  361.     /* From RKRM I&A, p. 65: */
  362.     if
  363.     (   !(DirHandle = (BPTR) Lock(size.path, ACCESS_READ))
  364.      || !(FIBPtr    = AllocDosObject(DOS_FIB, NULL))
  365.      || !(            Examine(DirHandle, FIBPtr))
  366.      ||  (FIBPtr->fib_DirEntryType <= 0) // if not a directory
  367.     )
  368.     {   failed = TRUE;
  369.     }
  370.  
  371.     strcpy(size.oldpath, size.path);
  372.     if (FIBPtr)
  373.     {   FreeDosObject(DOS_FIB, FIBPtr);
  374.         FIBPtr = NULL;
  375.     }
  376.     if (failed)
  377.     {   DisplayBeep(ScreenPtr);
  378.         GT_SetGadgetAttrs
  379.         (   BU99_Right,
  380.             MainWindowPtr, NULL,
  381.             GA_Disabled, FALSE,
  382.             TAG_DONE
  383.         );
  384.         GT_SetGadgetAttrs
  385.         (   BU99_Update,
  386.             MainWindowPtr, NULL,
  387.             GA_Disabled, FALSE,
  388.             TAG_DONE
  389.         );
  390.         GT_SetGadgetAttrs
  391.         (   BU99_Stop,
  392.             MainWindowPtr, NULL,
  393.             GA_Disabled, TRUE,
  394.             TAG_DONE
  395.         );
  396.         strcpy(size.path, size.oldpath);
  397.         GT_SetGadgetAttrs
  398.         (   ST81_Path,
  399.             MainWindowPtr, NULL,
  400.             GTST_String, size.path,
  401.             TAG_DONE
  402.         );
  403.         return;
  404.     }
  405.  
  406.     GT_SetGadgetAttrs
  407.     (   ST81_Path,
  408.         MainWindowPtr, NULL,
  409.         GTST_String, size.path,
  410.         TAG_DONE
  411.     );
  412.  
  413.     /* 3: Now we call Info() to ascertain the free bytes.
  414.           InfoDataPtr must be longword-aligned. */
  415.  
  416.     if (!(InfoDataPtr = AllocVec(sizeof(struct InfoData), MEMF_CLEAR)))
  417.     {   rq("Out of memory!");
  418.     }
  419.     if (Info(DirHandle, InfoDataPtr))
  420.     {   size.freeval =
  421.         (InfoDataPtr->id_NumBlocks - InfoDataPtr->id_NumBlocksUsed) *
  422.          InfoDataPtr->id_BytesPerBlock;
  423.         stcl_d(tempstring1, size.freeval);
  424.         templength = 10 - strlen(tempstring1);
  425.         strcpy(size.freestring, "");
  426.         for (i = 1; i <= templength; i++)
  427.             strcat(size.freestring, " ");
  428.         strcat(size.freestring, tempstring1);
  429.     } else strcpy(size.freestring, "         ?");
  430.     FreeVec(InfoDataPtr);
  431.     InfoDataPtr = NULL;
  432.  
  433.     /* 4: Now we are ready to begin the main part of the operation.
  434.  
  435.     size.topdir[]     = the 'owning' top-level directory for this subdir.
  436.                         Top-level dirs are owned by themselves.
  437.     size.bytes[]      = the size of this top-level directory/file.
  438.     size.entries      = how many top-level dirs, ie. how many names in the
  439.                         listview gadget.
  440.     size.path         = the path (drive, partition, etc.) the user is doing
  441.                         the report on.
  442.     size.stackentries = the current size of the stack.
  443.     DirNamesAllocated = the number of allocated chunks for the
  444.                         topdir names. */
  445.  
  446.     dup = 0;
  447.     if (size.finddup)
  448.     {   if (!( TablePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  449.         {   rq("Out of memory!");
  450.         }
  451.         if (!(OffsetPtr = AllocVec(MAX_FILES * sizeof(UBYTE),  NULL)))
  452.         {   rq("Out of memory!");
  453.     }   }
  454.  
  455.     // This must be allocated with AllocDosObject()
  456.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  457.     {   rq("Can't allocate DOS object!");
  458.     }
  459.  
  460.     eac->eac_LastKey = 0;
  461.     do
  462.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 2048, ED_SIZE, eac);
  463.         if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
  464.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  465.             eac = NULL;
  466.             rq("Can't examine path!");
  467.         }
  468.         if (eac->eac_Entries == 0)
  469.         {   ; /* ExAll() failed normally with no entries */
  470.             continue; /* more is USUALLY zero */
  471.         }
  472.  
  473.         // OK, ExAll() has generated up to 2K of data.
  474.         ead = (struct ExAllData *) EADataPtr;
  475.         do
  476.         {   /* use ead here */
  477.  
  478.             if (ead->ed_Type == -3 || ead->ed_Type == 2) // if a normal file or normal directory (ie. not a link)
  479.             {   size.entries++;
  480.                 if (size.entries == LIMIT_DIRS)
  481.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  482.                     eac = NULL;
  483.                     rq("Overflow!");
  484.                 }
  485.                 size.type[size.entries] = ead->ed_Type;
  486.                 if (size.entries > DirNamesAllocated)
  487.                 {   if (!(DirNamePtr[DirNamesAllocated + 1] = AllocMem(VLONGFIELD, MEMF_PUBLIC)))
  488.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  489.                         eac = NULL;
  490.                         rq("Out of memory!");
  491.                     }
  492.                     DirNamesAllocated++;
  493.                 }
  494.                 strcpy(DirNamePtr[size.entries], ead->ed_Name);
  495.                 if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  496.                 {   size.bytes[size.entries] = 0;
  497.                     strcpy(tempstring3, size.path);
  498.                     if (!AddPart(tempstring3, ead->ed_Name, VLONGFIELD))
  499.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  500.                         eac = NULL;
  501.                         rq("Can't add filename to pathname!");
  502.                     }
  503.                     push(tempstring3, size.entries);
  504.                 } else
  505.                 {   addduplicate("", ead->ed_Name);
  506.                     size.bytes[size.entries] = ead->ed_Size;
  507.             }   }
  508.  
  509.             /* get next ead */
  510.             ead = ead->ed_Next;
  511.         } while(ead);
  512.     } while(more);
  513.  
  514.     FreeDosObject(DOS_EXALLCONTROL, eac);
  515.     eac = NULL;
  516.     UnLock(DirHandle);
  517.     DirHandle = NULL;
  518.     pop();
  519.  
  520.     // Now handle the list.
  521.  
  522.     GT_SetGadgetAttrs
  523.     (   LV81_Listview,
  524.         MainWindowPtr,
  525.         NULL,
  526.         GTLV_Labels, (~0),
  527.         TAG_DONE
  528.     );
  529.  
  530. if (!stop)
  531. {   /* size.entries is the actual number of entries. The array elements are
  532.     from 1 to size.entries.
  533.  
  534.     bubble sort routine */
  535.  
  536.     for (i = size.entries; i >= 2; i--)
  537.     {   for (j = 2; j <= i; j++) 
  538.         {   if (size.bytes[j - 1] < size.bytes[j]) 
  539.             {   // swap them
  540.                 tempbytes = size.bytes[j - 1];
  541.                 size.bytes[j - 1] = size.bytes[j]; 
  542.                 size.bytes[j] = tempbytes;
  543.                 temptype = size.type[j - 1];
  544.                 size.type[j - 1] = size.type[j];
  545.                 size.type[j] = temptype;
  546.                 strcpy(tempname, DirNamePtr[j - 1]);
  547.                 strcpy(DirNamePtr[j - 1], DirNamePtr[j]);
  548.                 strcpy(DirNamePtr[j], tempname);
  549.     }   }   }
  550.  
  551.     getdate();
  552.     if (shared.log)
  553.     {   tempstring1[0] = QUOTE;
  554.         tempstring1[1] = 0;
  555.  
  556.         strcpy(logstring, "Path: ");
  557.         strcat(logstring, tempstring1);
  558.         strcat(logstring, size.path);
  559.         strcat(logstring, tempstring1);
  560.         strcat(logstring, " at ");
  561.         strcat(logstring, timestring);
  562.         strcat(logstring, " on ");
  563.         strcat(logstring, weekdaystring);
  564.         strcat(logstring, " ");
  565.         strcat(logstring, datestring);
  566.         strcat(logstring, ":\n");
  567.         if (!(FileHandle = (BPTR) Open(shared.output, MODE_READWRITE)))
  568.             rq("Can't open file for appending!");
  569.         Seek(FileHandle, 0, OFFSET_END);
  570.         writeline();
  571.     }
  572.  
  573.     // very long dirnames (truncated ones) are not selectable, unfortunately.
  574.     size.totalbytesval = 0;
  575.     for (i = 1; i <= size.entries; i++)
  576.     {   comma(size.bytes[i]);
  577.  
  578.         if (size.type[i] == 2)
  579.         {   strcpy(tempstring2, "*");
  580.             strcpy(tempstring3, "*");
  581.         } else
  582.         {   strcpy(tempstring2, " ");
  583.             strcpy(tempstring3, " ");
  584.         }
  585.  
  586.         if (strlen(DirNamePtr[i]) > TRUNCATE)
  587.             *(DirNamePtr[i] + TRUNCATE) = 0; // truncate
  588.         strcat(tempstring3, DirNamePtr[i]);
  589.         templength = TRUNCATE + 1 - strlen(DirNamePtr[i]);
  590.         if (templength >= 1)
  591.             for (j = 1; j <= templength; j++)
  592.                 strcat(tempstring3, " ");
  593.  
  594.         if (strlen(DirNamePtr[i]) > LVTRUNCATE)
  595.             *(DirNamePtr[i] + LVTRUNCATE) = 0; // truncate
  596.         strcat(tempstring2, DirNamePtr[i]); /* tempstring2 = "*<name>" */
  597.         templength = LVTRUNCATE + 1 - strlen(DirNamePtr[i]);
  598.         if (templength >= 1)
  599.             for (j = 1; j <= templength; j++)
  600.                 strcat(tempstring2, " "); /* tempstring2 = "*<name>   " */
  601.  
  602.         strcat(tempstring2, commastring);
  603.         strcat(tempstring3, commastring);
  604.  
  605.         AddNameToTail(&SizeList, tempstring2);
  606.         if (shared.log)
  607.         {   strcpy(logstring, tempstring3);
  608.             strcat(logstring, "\n");
  609.             writeline();
  610.         }
  611.         size.totalbytesval += size.bytes[i];
  612.     }
  613.  
  614.     comma(size.totalbytesval);
  615.     GT_SetGadgetAttrs
  616.     (   TE81_Total,
  617.         MainWindowPtr, NULL,
  618.         GTTX_Text, commastring,
  619.         TAG_DONE
  620.     );
  621.     comma(size.freeval);
  622.     GT_SetGadgetAttrs
  623.     (   TE81_Free,
  624.         MainWindowPtr,
  625.         NULL,
  626.         GTTX_Text, commastring,
  627.         TAG_DONE
  628.     );
  629.     if (shared.log)
  630.     {   strcpy(logstring, "\nPath bytes:                                         ");
  631.         comma(size.totalbytesval);
  632.         strcat(logstring, commastring);
  633.         strcat(logstring, "\nFree bytes:                                         ");
  634.         comma(size.freeval);
  635.         strcat(logstring, commastring);
  636.         strcat(logstring, "\n\n");
  637.         writeline();
  638.         Close(FileHandle);
  639.         FileHandle = NULL;
  640.     }
  641.     showduplicates();
  642. } else
  643. {   GT_SetGadgetAttrs
  644.     (   TE81_Total,
  645.         MainWindowPtr, NULL,
  646.         GTTX_Text, "",
  647.         TAG_DONE
  648.     );
  649.     comma(size.freeval);
  650.     GT_SetGadgetAttrs
  651.     (   TE81_Free,
  652.         MainWindowPtr,
  653.         NULL,
  654.         GTTX_Text, "",
  655.         TAG_DONE
  656.     );
  657.     GT_SetGadgetAttrs
  658.     (   LV81_DupListview,
  659.         MainWindowPtr,
  660.         NULL,
  661.         GTLV_Labels, NULL,
  662.         TAG_DONE
  663.     );
  664.     clearlist(&SizeResultList);
  665. }
  666.  
  667.     GT_SetGadgetAttrs
  668.     (   LV81_Listview,
  669.         MainWindowPtr,
  670.         NULL,
  671.         GTLV_Labels, &SizeList,
  672.         TAG_DONE
  673.     );
  674.     GT_SetGadgetAttrs
  675.     (   BU99_Right,
  676.         MainWindowPtr, NULL,
  677.         GA_Disabled, FALSE,
  678.         TAG_DONE
  679.     );
  680.     GT_SetGadgetAttrs
  681.     (   BU99_Update,
  682.         MainWindowPtr, NULL,
  683.         GA_Disabled, FALSE,
  684.         TAG_DONE
  685.     );
  686.     GT_SetGadgetAttrs
  687.     (   BU99_Stop,
  688.         MainWindowPtr, NULL,
  689.         GA_Disabled, TRUE,
  690.         TAG_DONE
  691.     );
  692.  
  693.     if (FileHandle) // this is in case the user clicked stop
  694.     {   Close(FileHandle);
  695.         FileHandle = NULL;
  696.     }
  697.     while(FileNamesAllocated)
  698.     {   FreeMem(FileNamePtr[FileNamesAllocated], VLONGFIELD);
  699.         FileNamePtr[FileNamesAllocated--] = NULL;
  700.     }
  701.     // We need the DirNamePtr[] array to remain valid, because the user
  702.     // can click on the listview gadget.
  703. }
  704.  
  705. MODULE void subdir(ULONG topdir)
  706. {   BOOL                 more;
  707.     TEXT                 tempstring[VLONGFIELD + 1];
  708.     BPTR                 DirHandle = NULL;
  709.     struct ExAllControl* eac       = NULL;
  710.     struct ExAllData*    ead;
  711.  
  712.     /* Instead of passing a pointer to the path, we use a global string.
  713.     There are memory corruption problems if you pass pointers to variables
  714.     which are really local to other functions.
  715.  
  716.     This is dynamically allocated as it must be at least word-aligned;
  717.     also remember not to allocate large arrays on the stack. */
  718.  
  719.     if (!(DirHandle = (BPTR) Lock(globalname, ACCESS_READ)))
  720.     {   DisplayBeep(ScreenPtr);
  721.         return;
  722.     }
  723.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  724.     {   UnLock(DirHandle);
  725.         DirHandle = NULL;
  726.         rq("Can't allocate DOS object!");
  727.     }
  728.  
  729.     eac->eac_LastKey = 0;
  730.     do
  731.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 2048, ED_SIZE, eac);
  732.         if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES))
  733.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  734.             eac = NULL;
  735.             UnLock(DirHandle);
  736.             DirHandle = NULL;
  737.             rq("Can't examine path!");
  738.         }
  739.         if (eac->eac_Entries == 0)
  740.         {   ; /* ExAll() failed normally with no entries */
  741.             continue; /* more is USUALLY zero */
  742.         }
  743.         ead = (struct ExAllData *) EADataPtr;
  744.  
  745.         do
  746.         {   /* use ead here */
  747.  
  748.             if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  749.             {   strcpy(tempstring, globalname);
  750.                 if (!AddPart(tempstring, ead->ed_Name, VLONGFIELD))
  751.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  752.                     eac = NULL;
  753.                     UnLock(DirHandle);
  754.                     DirHandle = NULL;
  755.                     rq("Can't add filename to pathname!");
  756.                 }
  757.                 push(tempstring, topdir);
  758.             } elif (ead->ed_Type == -3) // if it's a file
  759.             {   addduplicate(&globalname[pathlength], ead->ed_Name);
  760.                 size.bytes[topdir] += ead->ed_Size;
  761.             }
  762.  
  763.             /* get next ead */
  764.             ead = ead->ed_Next;
  765.         } while(ead);
  766.     } while(more);
  767.  
  768.     FreeDosObject(DOS_EXALLCONTROL, eac);
  769.     eac = NULL;
  770.     UnLock(DirHandle);
  771.     DirHandle = NULL;
  772.     // don't call pop() yourself!
  773. }
  774.  
  775. MODULE void pop(void)
  776. {   ULONG breakval;
  777.  
  778.     pathlength = strlen(size.path);
  779.     while (size.stackentries && !stop)
  780.     {   size.stackentries--;
  781.         strcpy(globalname, FileNamePtr[size.stackentries + 1]);
  782.         subdir(size.topdir[size.stackentries + 1]);
  783.         breakval = checkbreak();
  784.         if (breakval == 2)
  785.             cleanexit(EXIT_SUCCESS);
  786.         elif (breakval == 1)
  787.             stop = TRUE;
  788. }   }
  789. MODULE void push(STRPTR name, ULONG theindex)
  790. {   size.stackentries++;
  791.     if (size.stackentries == LIMIT_DIRS)
  792.         rq("Overflow!");
  793.     if (size.stackentries > FileNamesAllocated)
  794.     {   if (!(FileNamePtr[FileNamesAllocated + 1] = AllocMem(VLONGFIELD, MEMF_PUBLIC)))
  795.             rq("Out of memory!");
  796.         FileNamesAllocated++;
  797.     }
  798.     strcpy(FileNamePtr[size.stackentries], name);
  799.     size.topdir[size.stackentries] = theindex;
  800. }
  801.  
  802. AGLOBAL void size_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual)
  803. {   UWORD moveto;
  804.  
  805.     if (class == IDCMP_RAWKEY)
  806.     {   if (qual & IEQUALIFIER_CONTROL)
  807.         {   if (code == SCAN_UP)
  808.             {   GT_SetGadgetAttrs
  809.                 (   LV81_Listview,
  810.                     MainWindowPtr,
  811.                     NULL,
  812.                     GTLV_Top, 0,
  813.                     TAG_DONE
  814.                 );
  815.             } elif (code == SCAN_DOWN)
  816.             {   if (size.entries > 15)          // this number must change
  817.                 {   moveto = size.entries - 15; // if the height of the
  818.                 } else moveto = 0;              // listview changes
  819.                 GT_SetGadgetAttrs
  820.                 (   LV81_Listview,
  821.                     MainWindowPtr,
  822.                     NULL,
  823.                     GTLV_Top, moveto,
  824.                     TAG_DONE
  825.                 );
  826.     }   }   }
  827.     elif (class == IDCMP_VANILLAKEY)
  828.     {   code = toupper(code);
  829.         if (code == ESCAPE)
  830.         {   page = 0;
  831.         } elif (code == 'A')
  832.             parent();
  833.         elif (code == 'R')
  834.             root();
  835.         elif (code == '.')
  836.             pathasl();
  837.         elif (code == 'P')
  838.         {   ActivateGadget(ST81_Path, MainWindowPtr, NULL);
  839.         } elif (code == 'L')
  840.             fliplog(TRUE);
  841.         elif (code == 'O')
  842.         {   ActivateGadget(ST99_Output, MainWindowPtr, NULL);
  843.         } elif (code == 'U')
  844.             updatesize();
  845.         elif (code == 'D')
  846.         {   flipfind(TRUE);
  847.     }   }
  848.     elif (class == IDCMP_GADGETUP)
  849.     {   /* IDCMP_GADGETUP is sent by the string gadget
  850.         when the user presses RETURN, ENTER, Help, Tab
  851.         or Shift-Tab inside the string gadget. */
  852.  
  853.         if (addr == BU99_Right)
  854.         {   page = 0;
  855.         } elif (addr == BU99_Update)
  856.         {   updatesize();
  857.         } elif (addr == BU81_PathASL)
  858.         {   pathasl();
  859.         } elif (addr == ST81_Path)
  860.         {   pathstring();
  861.         } elif (addr == CB99_Log)
  862.         {   fliplog(FALSE);
  863.         } elif (addr == ST99_Output)
  864.         {   outputstring();
  865.         } elif (addr == BU99_OutputASL)
  866.         {   outputasl();
  867.         } elif (addr == BU81_Root)
  868.         {   root();
  869.         } elif (addr == BU81_Parent)
  870.         {   parent();
  871.         } elif (addr == CB81_Find)
  872.         {   flipfind(FALSE);
  873.         } elif (addr == LV81_Listview)
  874.         {   /* code is the position within the list, starting from 0. */
  875.  
  876.             if (code + 1 <= size.entries && size.type[code + 1] == 2)
  877.             {   if (!(AddPart(size.path, DirNamePtr[code + 1], VLONGFIELD + 1)))
  878.                     rq("Can't add filename to pathname!");
  879.                 else updatesize();
  880. }   }   }   }
  881.  
  882. AGLOBAL void size_exit(void)
  883. {   if (DirHandle)
  884.     {   UnLock(DirHandle);
  885.         DirHandle = NULL;
  886.     }
  887.     if (FileHandle)
  888.     {   Close(FileHandle);
  889.         FileHandle = NULL;
  890.     }
  891.  
  892.     // Only call this if the list gadget is detached or not present.
  893.     // (ie. after closewindow()).
  894.     clearlist(&SizeList);
  895.     clearlist(&SizeResultList);
  896.  
  897.     while(FileNamesAllocated)
  898.     {   FreeMem(FileNamePtr[FileNamesAllocated], VLONGFIELD);
  899.         FileNamePtr[FileNamesAllocated--] = NULL;
  900.     }
  901.     while( DirNamesAllocated)
  902.     {   FreeMem( DirNamePtr[ DirNamesAllocated], VLONGFIELD);
  903.          DirNamePtr[ DirNamesAllocated--] = NULL;
  904. }   }
  905.  
  906. MODULE void parent(void)
  907. {   BPTR DirHandle    = NULL,
  908.          ParentHandle = NULL;
  909.  
  910.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  911.         rq("Can't lock directory!");
  912.     if (!(ParentHandle = ParentDir(DirHandle)))
  913.     {   /* It returned a NULL lock; ie. a lock on SYS:
  914.         That is not what we want. */
  915.         ParentHandle = DirHandle;
  916.     }
  917.     if (!NameFromLock(ParentHandle, size.path, VLONGFIELD))
  918.         rq("Can't get name from lock!");
  919.     UnLock(DirHandle);
  920.     DirHandle = NULL;
  921.  
  922.     updatesize();
  923. }
  924.  
  925. MODULE void root(void)
  926. {   BPTR  DirHandle    = NULL,
  927.           ParentHandle = NULL;
  928.     ABOOL rootdone     = FALSE;
  929.  
  930.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  931.         rq("Can't lock directory!");
  932.     do
  933.     {   if (!(ParentHandle = ParentDir(DirHandle)))
  934.         {   /* It returned a NULL lock; ie. a lock on SYS:
  935.                That is not what we want. */
  936.             ParentHandle = DirHandle;
  937.             rootdone = TRUE;
  938.         } else DirHandle = ParentHandle;
  939.     } while (!rootdone);
  940.     if (!NameFromLock(ParentHandle, size.path, VLONGFIELD))
  941.         rq("Can't get name from lock!");
  942.     UnLock(DirHandle);
  943.     DirHandle = NULL;
  944.  
  945.     updatesize();
  946. }
  947.  
  948. MODULE void pathasl(void)
  949. {   strcpy(asldir, size.path);
  950.     if (dirasl()) // path for ASL must be valid?
  951.     {   strcpy(size.path, aslresult);
  952.         GT_SetGadgetAttrs
  953.         (   ST81_Path,
  954.             MainWindowPtr, NULL,
  955.             GTST_String, size.path,
  956.             TAG_DONE
  957.         );
  958.         updatesize();
  959. }   }
  960.  
  961. MODULE void pathstring(void)
  962. {   strcpy
  963.     (   size.path,
  964.         ((struct StringInfo *) ST81_Path->SpecialInfo)->Buffer
  965.     );
  966.     updatesize();
  967. }
  968.  
  969. MODULE void comma(ULONG value)
  970. {   ABOOL yeah = FALSE;
  971.  
  972.     strcpy(commastring, " ,   ,   ,   ");
  973.     //                    1   5   9
  974.  
  975.     valuestring[ 0] = '0' + (value / 1000000000);
  976.     value %= 1000000000;
  977.     if (valuestring[ 0] != '0')
  978.     {   commastring[0] = valuestring[0];
  979.         yeah = TRUE;
  980.     } else
  981.     {   commastring[ 0] = ' ';
  982.         commastring[ 1] = ' ';
  983.     }
  984.  
  985.     valuestring[ 1] = '0' + (value /  100000000);
  986.     value %=  100000000;
  987.     if (yeah || valuestring[1] != '0')
  988.     {   commastring[2] = valuestring[1];
  989.         yeah = TRUE;
  990.     } else commastring[2] = ' ';
  991.  
  992.     valuestring[ 2] = '0' + (value /   10000000);
  993.     value %=   10000000;
  994.     if (yeah || valuestring[2] != '0')
  995.     {   commastring[3] = valuestring[2];
  996.         yeah = TRUE;
  997.     } else commastring[3] = ' ';
  998.  
  999.     valuestring[ 3] = '0' + (value /    1000000);
  1000.     value %=    1000000;
  1001.     if (yeah || valuestring[3] != '0')
  1002.     {   commastring[4] = valuestring[3];
  1003.         yeah = TRUE;
  1004.     } else
  1005.     {   commastring[4] = ' ';
  1006.         commastring[5] = ' ';
  1007.     }
  1008.  
  1009.     valuestring[ 4] = '0' + (value /     100000);
  1010.     value %=     100000;
  1011.     if (yeah || valuestring[4] != '0')
  1012.     {   commastring[6] = valuestring[4];
  1013.         yeah = TRUE;
  1014.     } else commastring[6] = ' ';
  1015.  
  1016.     valuestring[ 5] = '0' + (value /      10000);
  1017.     value %=      10000;
  1018.     if (yeah || valuestring[5] != '0')
  1019.     {   commastring[7] = valuestring[5];
  1020.         yeah = TRUE;
  1021.     } else commastring[7] = ' ';
  1022.  
  1023.     valuestring[ 6] = '0' + (value /       1000);
  1024.     value %=       1000;
  1025.     if (yeah || valuestring[6] != '0')
  1026.     {   commastring[8] = valuestring[6];
  1027.         yeah = TRUE;
  1028.     } else
  1029.     {   commastring[8] = ' ';
  1030.         commastring[9] = ' ';
  1031.     }
  1032.  
  1033.     valuestring[ 7] = '0' + (value /        100);
  1034.     value %=        100;
  1035.     if (yeah || valuestring[7] != '0')
  1036.     {   commastring[10] = valuestring[7];
  1037.         yeah = TRUE;
  1038.     } else commastring[10] = ' ';
  1039.  
  1040.     valuestring[ 8] = '0' + (value /         10);
  1041.     value %=         10;
  1042.     if (yeah || valuestring[8] != '0')
  1043.     {   commastring[11] = valuestring[8];
  1044.         yeah = TRUE;
  1045.     } else commastring[11] = ' ';
  1046.  
  1047.     valuestring[ 9] = '0' +  value              ;
  1048.     commastring[12] = valuestring[9];
  1049. }
  1050.  
  1051. MODULE ABOOL dirasl(void)
  1052. {   struct FileRequester* ASLRqPtr;
  1053.     ABOOL                 success;
  1054.  
  1055.     if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "~(#?.info)", ASL_Window, MainWindowPtr, ASL_ExtFlags1, FIL1F_NOFILES, TAG_DONE)))
  1056.     {   rq("Can't create ASL request!");
  1057.     }
  1058.     if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ path selector", ASL_FuncFlags, FILF_PATGAD, TAG_DONE))
  1059.     {   strcpy(aslresult, ASLRqPtr->rf_Dir);
  1060.         success = TRUE;
  1061.     } else success = FALSE;
  1062.     FreeAslRequest(ASLRqPtr);
  1063.     return(success);
  1064. }
  1065.  
  1066. MODULE void showduplicates(void)
  1067. {   ULONG                 breakval, i, j, k;
  1068.     ABOOL                 found  = FALSE,
  1069.                           success;
  1070.     struct DateTime       DateTime;
  1071.     LONG                  templength;
  1072.     struct FileInfoBlock* FIBPtr = NULL;
  1073.     TEXT                  tempstring[VLONGFIELD + 1],
  1074.                           tempstring2[VLONGFIELD + 1];
  1075.  
  1076.     DateTime.dat_Format  = FORMAT_DOS;
  1077.     DateTime.dat_Flags   = NULL;
  1078.     DateTime.dat_StrDay  = NULL;
  1079.     DateTime.dat_StrDate = datestring;
  1080.     DateTime.dat_StrTime = NULL;
  1081.  
  1082.     if (size.finddup)
  1083.     {   GT_SetGadgetAttrs
  1084.         (   LV81_DupListview,
  1085.             MainWindowPtr,
  1086.             NULL,
  1087.             GTLV_Labels, NULL,
  1088.             TAG_DONE
  1089.         );
  1090.         clearlist(&SizeResultList);
  1091.  
  1092.         if (shared.log)
  1093.         {   strcpy(logstring, "Duplicates found:\n");
  1094.             if (!(FileHandle = (BPTR) Open(shared.output, MODE_READWRITE)))
  1095.                 rq("Can't open file for appending!");
  1096.             Seek(FileHandle, 0, OFFSET_END);
  1097.             writeline();
  1098.         }
  1099.         for (i = 0; i <= dup; i++)
  1100.         {   breakval = checkbreak();
  1101.             if (breakval == 2)
  1102.             {   cleanexit(EXIT_SUCCESS);
  1103.             } elif (breakval == 1)
  1104.             {   stop = TRUE;
  1105.                 break;
  1106.             }
  1107.             for (j = 0; j <= dup; j++)
  1108.             {   if (i != j && !stricmp(TablePtr[i] + OffsetPtr[i], TablePtr[j] + OffsetPtr[j]))
  1109.                 {   found = TRUE;
  1110.  
  1111.                     if (*(TablePtr[i]) != '/')
  1112.                     {   strcpy(tempstring, TablePtr[i]);
  1113.                     } else
  1114.                     {   strcpy(tempstring, TablePtr[i] + 1);
  1115.                     }
  1116.                     if (strlen(tempstring) > TRUNCATE)
  1117.                     {   *(tempstring + TRUNCATE) = 0; // truncate
  1118.                     }
  1119.                     templength = TRUNCATE + 1 - strlen(tempstring);
  1120.                     if (templength >= 1)
  1121.                     {    for (k = 1; k <= templength; k++)
  1122.                          {   strcat(tempstring, " ");
  1123.                     }    }
  1124.  
  1125.                     strcpy(tempstring2, size.path);
  1126.                     strcat(tempstring2, TablePtr[i]);
  1127.                     success = FALSE;
  1128.                     if (DirHandle  = (BPTR) Lock(tempstring2, ACCESS_READ))
  1129.                     {   if (FIBPtr =        AllocDosObject(DOS_FIB, NULL))
  1130.                         {   success = TRUE;
  1131.  
  1132.                             if (Examine(DirHandle, FIBPtr))
  1133.                             {   comma(FIBPtr->fib_Size);
  1134.                                 strcat(tempstring, commastring);
  1135.                             } else
  1136.                             {   strcat(tempstring, "            ?");
  1137.                             }
  1138.                             strcat(tempstring, " ");
  1139.  
  1140.                             DateTime.dat_Stamp   = FIBPtr->fib_Date;
  1141.                             if (DateToStr(&DateTime))
  1142.                             {   strcat(tempstring, datestring);
  1143.                             } else
  1144.                             {   strcat(tempstring, "        ?");
  1145.                             }
  1146.                             strcat(tempstring, " ");
  1147.  
  1148.                             FreeDosObject(DOS_FIB, FIBPtr);
  1149.                             FIBPtr = NULL;
  1150.                             UnLock(DirHandle);
  1151.                             DirHandle = NULL;
  1152.                     }   }
  1153.                     if (!success)
  1154.                     {   strcat(tempstring, "            ?          ?");
  1155.                     }
  1156.  
  1157.                     AddNameToTail(&SizeResultList, tempstring);
  1158.                     if (shared.log)
  1159.                     {   strcpy(logstring, " ");
  1160.                         strcat(logstring, tempstring);
  1161.                         strcat(logstring, "\n");
  1162.                         writeline();
  1163.                     }
  1164.                     break;
  1165.         }   }   }
  1166.         for (i = 0; i < dup; i++)
  1167.         {   FreeVec(TablePtr[i]);
  1168.         }
  1169.         dup = 0;
  1170.         FreeVec(OffsetPtr);
  1171.         OffsetPtr = NULL;
  1172.         FreeVec(TablePtr);
  1173.         TablePtr = NULL;
  1174.  
  1175.         if (shared.log)
  1176.         {   if (!found)
  1177.             {   strcat(logstring, " None\n");
  1178.             }
  1179.             strcat(logstring, "\n");
  1180.             writeline();
  1181.             Close(FileHandle);
  1182.             FileHandle = NULL;
  1183.         }
  1184.  
  1185.         GT_SetGadgetAttrs
  1186.         (   LV81_DupListview,
  1187.             MainWindowPtr,
  1188.             NULL,
  1189.             GTLV_Labels, &SizeResultList,
  1190.             TAG_DONE
  1191.         );
  1192. }   }
  1193.  
  1194. MODULE void clearlist(struct List* ListPtr)
  1195. {   if (!(ListPtr->lh_Head->ln_Succ)) // if list is non-empty
  1196.     {   FreeNameNodes(ListPtr);
  1197.     }
  1198.     NewList(ListPtr); // prepare for reuse
  1199. }
  1200.  
  1201. MODULE void addduplicate(STRPTR path, STRPTR filename)
  1202. {   TEXT tempstring[257];
  1203.  
  1204.     if (size.finddup)
  1205.     {   OffsetPtr[dup] = strlen(path);
  1206.         strcpy(tempstring, path);
  1207.         if (!AddPart(tempstring, filename, 256))
  1208.         {   rq("AddPart() failed!");
  1209.         }
  1210.         if (!(TablePtr[dup] = AllocVec(strlen(tempstring) + 1, NULL)))
  1211.         {   rq("Out of memory!");
  1212.         }
  1213.         strcpy(TablePtr[dup++], tempstring);
  1214.         if (dup >= MAX_FILES)
  1215.         {   rq("Too many files!");
  1216. }   }   }
  1217.  
  1218. MODULE void flipfind(ABOOL keyboard)
  1219. {   if (keyboard)
  1220.     {   if (CB81_Find->Flags & GFLG_SELECTED)
  1221.         {   size.finddup = FALSE;
  1222.         } else
  1223.         {   size.finddup = TRUE;
  1224.     }   }
  1225.     else
  1226.     {   if (CB81_Find->Flags & GFLG_SELECTED)
  1227.         {   size.finddup = TRUE;
  1228.         } else
  1229.         {   size.finddup = FALSE;
  1230.     }   }
  1231.  
  1232.     GT_SetGadgetAttrs
  1233.     (   CB81_Find,
  1234.         MainWindowPtr, NULL,
  1235.         GTCB_Checked, size.finddup,
  1236.         TAG_DONE
  1237.     );
  1238.     GT_SetGadgetAttrs
  1239.     (   LV81_DupListview,
  1240.         MainWindowPtr, NULL,
  1241.         GA_Disabled, !size.finddup,
  1242.         TAG_DONE
  1243.     );
  1244. }
  1245.  
  1246. MODULE void writeline(void)
  1247. {   /* The file is opened just before the first call to writeline()
  1248.     (when the date, time, etc. is written). Then we keep the file open
  1249.     and do our scan. Then we write out the results a line at a time,
  1250.     then the free and total bytes, then close the file.
  1251.       If we are also doing duplicates, we now do our thinking, and then
  1252.     reopen the file, write the results a line at a time, then close the
  1253.     file. */
  1254.  
  1255.     if (FPuts(FileHandle, logstring))
  1256.     {   Close(FileHandle);
  1257.         rq("Can't append to file!");
  1258. }   }
  1259.